﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using TL_Cloud.Common.cache;

namespace TL_Cloud.API.Controllers
{
    /// <summary>
    ///  大文件上传控制器
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class BigFileUploadController : Controller
    {
        private readonly ICache cache;
        private readonly IHostingEnvironment hostingEnvironment;
        /// <summary>
        ///  大文件上传的控制器
        /// </summary>
        /// <param name="_cache"></param>
        /// <param name="_hostingEnvironment"></param>
        public BigFileUploadController(ICache _cache, IHostingEnvironment _hostingEnvironment)
        {
            this.cache = _cache;
            this.hostingEnvironment = _hostingEnvironment;
        }


        #region 文件分片上传

      


        /// <summary>
        /// 上传附件分片数据
        /// </summary> 
        /// <returns></returns>
        [HttpPost(Name ="BigFilePostFile")]
        public async Task<IActionResult> Post(uploadFileInfo upfileInfo, IFormFile fromfile)
        {
            //表示正在上传
            if (upfileInfo.oper == 0)
            {
                if (fromfile != null)
                {
                    SaveChunkAnnexes(upfileInfo.fileGuid, upfileInfo.chunk, fromfile.OpenReadStream());
                    return Ok("文件上传成功");
                }
                else
                {
                    return BadRequest("上传文件不存在");
                }
            }
            else if (upfileInfo.oper == -1) //表示正在进行删除
            {
                RemoveChunkAnnexes(upfileInfo.fileGuid, upfileInfo.chunks);
                return Ok("删除上传文件缓存成功");
            }
            else if (upfileInfo.oper == 1) //表示上传完成开始进行合并
            {
                string guidFile = Guid.NewGuid().ToString() + Path.GetExtension(upfileInfo.fileName);
                string webfile = $"/upload/resource/{guidFile}";
                string filePath = System.IO.Path.Combine(hostingEnvironment.ContentRootPath, "upload", "resource", guidFile);
                bool res = SaveAnnexes(filePath, upfileInfo.fileGuid, upfileInfo.chunks);
                if (res)
                {
                    return Ok (new
                    {
                        virtualPath = webfile,
                        url = string.Format("{0}{1}","http://localhost:5000/", webfile),
                        fileName = upfileInfo.fileName
                    }); 
                }
                else
                {
                    return BadRequest("文件合并失败");
                }
            }
            else
            {
                return NotFound("请求参数不正确");
            } 
        } 
        /// <summary>
        /// 对分块的文件进行合并保存
        /// </summary>
        /// <param name="saveFile">要保存的文件路径</param>
        /// <param name="fileGuid">文件主键</param>
        /// <param name="chunks">文件总共分多少片</param>
        /// <returns></returns>
        private bool SaveAnnexes(string saveFile, string fileGuid, int chunks)
        {
            try
            {
                //获取文件完整文件名(包含绝对路径) 
                string FileEextension = Path.GetExtension(saveFile); 
                //创建文件夹
                string path = Path.GetDirectoryName(saveFile);
                if (System.IO.Directory.Exists(path) == false)
                {
                    Directory.CreateDirectory(path);
                }

                long filesize = SaveAnnexesToFile(fileGuid, saveFile, chunks);
                if (filesize == -1)// 表示保存失败
                {
                    RemoveChunkAnnexes(fileGuid, chunks);
                    return false;
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 分块文件前缀
        /// </summary>
        private const string cacheKey = "TL_AnnexesFile";
        /// <summary>
        /// 分块对应的存储数据库
        /// </summary>
        private const int annexes = 3;
        /// <summary>
        /// 保存分片附件
        /// </summary>
        /// <param name="fileGuid">文件主键</param>
        /// <param name="chunk">分片文件序号</param>
        /// <param name="fileStream">文件流</param>
        private void SaveChunkAnnexes(string fileGuid, int chunk, Stream fileStream)
        {
            try
            {
                byte[] bytes = new byte[fileStream.Length];
                fileStream.Read(bytes, 0, bytes.Length);
                cache.WriteByte(cacheKey + chunk + "_" + fileGuid, bytes, annexes);
            }
            catch
            {
            }
        }

        /// <summary>
        /// 保存附件到文件中
        /// </summary>
        /// <param name="fileGuid">文件主键</param>
        /// <param name="filePath">文件路径</param>
        /// <param name="chunks">总共分片数</param>
        /// <returns>-1:表示保存失败</returns>
        private long SaveAnnexesToFile(string fileGuid, string filePath, int chunks)
        {
            try
            {
                long filesize = 0;
                //创建一个FileInfo对象
                FileInfo file = new FileInfo(filePath);
                //创建文件
                FileStream fs = file.Create();
                for (int i = 0; i < chunks; i++)
                {
                    byte[] bufferByRedis = cache.ReadByte(cacheKey + i + "_" + fileGuid, annexes);
                    if (bufferByRedis == null)
                    {
                        return -1;
                    }
                    //写入二进制流
                    fs.Write(bufferByRedis, 0, bufferByRedis.Length);
                    filesize += bufferByRedis.Length;
                    cache.Remove(cacheKey + i + "_" + fileGuid, annexes);
                }
                //关闭文件流
                fs.Close();

                return filesize;
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>
        /// 移除的文件的分块
        /// </summary>
        /// <param name="fileGuid"></param>
        /// <param name="chunks"></param>
        private void RemoveChunkAnnexes(string fileGuid, int chunks)
        {
            try
            {
                for (int i = 0; i < chunks; i++)
                {
                    cache.Remove(cacheKey + i + "_" + fileGuid, annexes);
                }
            }
            catch
            {

            }
        }


        #endregion



    }
    /// <summary>
    /// 上传文件信息
    /// </summary>
    public class uploadFileInfo
    {
        /// <summary>
        /// 操作动作  0:上传  1:合并  -1:移除
        /// </summary>
        public int oper { get; set; }

        /// <summary>
        /// 块号
        /// </summary>
        public int chunk { get; set; }

        /// <summary>
        /// 总块数
        /// </summary>
        public int chunks { get; set; }
        /// <summary>
        /// 文件guid编号
        /// </summary>
        public string fileGuid { get; set; }

        /// <summary>
        /// 文件名称
        /// </summary>
        public string fileName { get; set; }

    }
}
